package org.example.auth.service.authStrategy;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import org.example.auth.config.properties.CaptchaProperties;
import org.example.auth.domain.LoginUserDetails;
import org.example.auth.domain.PasswordLoginBody;
import org.example.auth.service.IAuthStrategy;
import org.example.auth.service.IAuthUserStrategy;
import org.example.auth.service.SysLoginService;
import org.example.common.core.constants.Constants;
import org.example.common.core.constants.GlobalConstants;
import org.example.common.core.constants.TenantConstants;
import org.example.common.core.domain.model.LoginModel;
import org.example.common.core.domain.model.LoginUser;
import org.example.common.core.enums.DeviceType;
import org.example.common.core.enums.GrantUser;
import org.example.common.core.exception.ServiceException;
import org.example.common.core.exception.oauth.CaptchaException;
import org.example.common.core.exception.oauth.CaptchaExpireException;
import org.example.common.core.utils.MessageUtils;
import org.example.common.core.utils.StringUtils;
import org.example.common.core.utils.ValidatorUtils;
import org.example.common.redis.utils.LoginHelper;
import org.example.common.redis.utils.RedisUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

/**
 * 密码登录
 */
@Service("password"+IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class PasswordAuthStrategy implements IAuthStrategy {

    private final SysLoginService sysLoginService;
    private final CaptchaProperties captchaProperties;

    @Override
    public UserDetails authentication(UsernamePasswordAuthenticationToken authenticationToken) {
        Object object= authenticationToken.getDetails();
        PasswordLoginBody loginBody;
        JSONObject jsonObject=JSON.parseObject(JSON.toJSONString(object));
        boolean validataCodeFlag=true;
        if(ObjectUtil.isNotNull(object)&&jsonObject.containsKey("grant_user")){
            loginBody=JSON.parseObject(JSON.toJSONString(object),PasswordLoginBody.class);
        }else{
            loginBody=new PasswordLoginBody();
            loginBody.setUsername(authenticationToken.getPrincipal().toString());
            loginBody.setPassword(authenticationToken.getCredentials().toString());
            loginBody.setGrant_user(GrantUser.MOBILE);
            loginBody.setDevice_type(DeviceType.UNDEFINED.getCode());
            loginBody.setTenant_id(TenantConstants.DEFAULT_TENANT_ID);
            loginBody.setExpires_in(Constants.ACCESS_TOKEN_VALIDITY_SECONDS);
            validataCodeFlag=false;
        }
        ValidatorUtils.validate(loginBody);
        if (captchaProperties.getEnabled()&&validataCodeFlag) {
            validateCaptcha(loginBody.getTenant_id(), loginBody.getUsername(),
                    loginBody.getDevice_type(), loginBody.getCode(),loginBody.getUuid());
        }
        sysLoginService.checkTenant(loginBody.getTenant_id());

        LoginUser loginUser=IAuthUserStrategy.getLoginUserByUsername(loginBody.getGrant_user().getCode(),
                loginBody.getTenant_id(),loginBody.getUsername());
        if(ObjectUtil.isNull(loginUser)){
            throw new ServiceException("用户不存在");
        }
        sysLoginService.checkLogin(loginBody.getGrant_type(),loginBody.getTenant_id(),
                loginBody.getUsername(),loginBody.getDevice_type(),
                ()->!BCrypt.checkpw(loginBody.getPassword(), loginUser.getPassword()));

        LoginModel loginModel=LoginModel.create();
        loginModel.setTimeout(loginBody.getExpires_in());
        loginModel.setToken(StringUtils.getUUID());
        loginModel.setDevice(loginBody.getDevice_type());
        loginModel.setGrantUser(loginBody.getGrant_user().getCode());
        LoginHelper.login(loginUser,loginModel);

        sysLoginService.recordLogininfor(loginUser.getTenantId(),loginUser.getUsername(),loginModel.getDevice(),Constants.SUCCESS,MessageUtils.message("user.login.success"));

        LoginUserDetails loginUserDetails= new LoginUserDetails(loginBody.getUsername(),
                loginBody.getPassword(),
                AuthorityUtils.createAuthorityList());
        loginUserDetails.setGrantUser(loginModel.getGrantUser());
        loginUserDetails.setDeviceType(loginModel.getDevice());
        loginUserDetails.setToken(loginModel.getToken());
        loginUserDetails.setTenantId(loginBody.getTenant_id());
        return loginUserDetails;
    }


    private void validateCaptcha(String tenantId, String username, String deviceType,String code, String uuid) {
        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
        String captcha = RedisUtils.getCacheObject(verifyKey);
        RedisUtils.deleteObject(verifyKey);
        if (captcha == null) {
            sysLoginService.recordLogininfor(tenantId, username,deviceType, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            sysLoginService.recordLogininfor(tenantId, username,deviceType, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
            throw new CaptchaException();
        }
    }
}
